package cn.learn.jdk8new.stream;

import cn.learn.jdk8new.Employee;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 3、终止操作（终端操作）
 *
 * @author huangyezhan
 * @version 1.0
 * @date 2020年03月24日15:03
 */
public class StreamDemo3 {

    private List<Employee> employees = Arrays.asList(
            new Employee("张三", 28, "天河", 5555.8, Employee.Status.BUSY),
            new Employee("李四", 28, "荔湾", 15886.5, Employee.Status.FREE),
            new Employee("王五", 30, "白云", 8886.4, Employee.Status.VOCATTION),
            new Employee("赵六", 41, "花都", 6786.1, Employee.Status.BUSY),
            new Employee("田七", 36, "从化", 13886.7, Employee.Status.BUSY)
    );

    /**
     * 查找与匹配
     * <p>
     * allMatch     检查是否匹配所有元素
     * anyMatch     检查是否至少匹配一个元素
     * noneMatch    检查是否美哟与匹配所有的元素
     * findFirst    返回第一个元素
     * findAny      返回当前流中的任意元素（用parallelStream，它是多线程并线，那个线程先找到就算那个；stream是串行，只会找到第一个）
     * count        返回流中元素的个数
     * max          返回流中最大的值
     * min          返回流中最小的值
     */
    @Test
    public void test1() {
        boolean b1 = employees.stream()
                .allMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);

        boolean b2 = employees.stream()
                .anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);

        boolean b3 = employees.stream()
                .noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b3);

        //用Optional容器处理万一为空的情况，用它的orElse去另外赋一个值给它，相当于sql的 IFNULL 的用法
        Optional<Employee> op = employees.stream()
                .sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary())) //倒序
                //.sorted(Comparator.comparingDouble(Employee::getSalary))  //顺序
                .findFirst();
        Employee ee = op.orElse(new Employee());
        System.out.println(ee);

        //stream            是串行，回到符合条件的第一个；
        //parallelStream    并行，多个线程一起找，谁先找到算谁的
        Employee e2 = employees.parallelStream().findAny().orElse(new Employee());
        System.out.println(e2);

        long count = employees.stream().count();
        System.out.println("计算数量：" + count);

        Optional<Employee> max = employees.stream()
                //.max((emp1, emp2) -> Double.compare(emp1.getSalary(), emp2.getSalary()))
                .max(Comparator.comparingDouble(Employee::getSalary));
        System.out.println(max.get());

        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                //.min((emp1, emp2) -> Double.compare(emp1.doubleValue(), emp2.doubleValue()))
                .min(Double::compare);
        System.out.println(min.get());
    }

    /**
     * 归约
     * reduce(T identity, BinaryOperator) / reduce( BinaryOperator )
     * 可以将流中元素反复结合起来,得到一个值
     */
    @Test
    public void test2() {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
        Integer sum = list.stream()
                .reduce(0, Integer::sum);//identity累计恒等值（在结果的基础上加上identity）
        System.out.println(sum);

        Optional<Double> op = employees.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);   //不是从0开始的，有可能值为空；所以用Optional接受
        System.out.println(op.get());


        Double reduce = employees.stream()
                .map(Employee::getSalary)
                .reduce(0d, (x, y) -> x + y);
        System.out.println(reduce);
    }

    /**
     * 收集
     * collect  将流转换为其他形式。接受一个Collectors接口实现，用于Stream中元素做汇总的方法
     */
    @Test
    public void test3() {
        //放list集合
        List<String> list = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        System.out.println(list);

        //放set集合中
        Set<String> set = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        System.out.println(set);

        //放不同的集合中
        HashSet<String> hs = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        System.out.println(hs);
    }

    @Test
    public void test4() throws Exception {
        //总数
        Long count = employees.stream()
                .collect(Collectors.counting());
        System.out.println("总数：" + count);

        //平均值
        Double avg = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println("平均值：" + avg);

        //总和
        Double sum = employees.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println("总和：" + sum);

        //最大值
        Optional<Employee> max = employees.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());

        Optional<Double> min = employees.stream()
                .map(Employee::getSalary)
                .collect(Collectors.minBy(Double::compare));

        System.out.println(min.get());
    }

    @Test
    public void test5() throws Exception {
        DoubleSummaryStatistics dss = employees.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        double avg   = dss.getAverage();
        long   count = dss.getCount();
        double sum   = dss.getSum();
        double max   = dss.getMax();
        double min   = dss.getMin();
    }

    //分组
    @Test
    public void test6() throws Exception {
        Map<Employee.Status, List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        System.out.println(map);
    }

    //多重分组（自定义规则分组）
    @Test
    public void test7() throws Exception {
        //通过员工状态进行分组
        Map<Employee.Status, Map<String, List<Employee>>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy(e -> {
                    if (e.getAge() < 30) {
                        return "青年";
                    } else if (e.getAge() < 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));

        System.out.println(map);
    }

    //分区
    @Test
    public void test8() throws Exception {
        Map<Boolean, List<Employee>> map = employees.stream()
                .collect(Collectors.partitioningBy(e -> e.getSalary() > 8000));

        System.out.println(map);
    }

    //连接字符串
    @Test
    public void test9() throws  Exception{
        String collect = employees.stream()
                .map(Employee::getName)
                .collect(Collectors.joining("，"));
        System.out.println(collect);
    }

}
